{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### redis工具类封装-从单节点到集群环境实现\n",
    "#### 引言\n",
    "在接口测试和实际项目开发中，我们经常需要从redis中获取验证码等数作为测试参数，为了提高代码复用性和可维护性，本文将介绍如何封装redis工具类，实现单节点及集群环境的数据操作。\n",
    "#### 环境准备\n",
    "首先需要安装redis相关依赖：\n",
    "```bash\n",
    "pip install redis\n",
    "pip install redis-cluster # 集群环境需要\n",
    "```\n",
    "#### 1.配置文件设计\n",
    "采用ini格式的配置文件统一管理redis连接信息：\n",
    "```shell\n",
    "[redis]\n",
    "# 单节点配置\n",
    "host = xxx.xxx.xxx.xxx\n",
    "prot = 6379\n",
    "username = \n",
    "password = xxx\n",
    "db = 0\n",
    "\n",
    "# 集群节点配置\n",
    "nodes = host1:6379,host2:6379\n",
    "```\n",
    "\n",
    "#### 2.redis工具类实现\n",
    "##### 2.1基础架构\n",
    "```python\n",
    "import redis\n",
    "from redis.cluster import RedisCluster\n",
    "\n",
    "class RedisClient:\n",
    "    def __init__(self):\n",
    "        self.config = {}\n",
    "        self._init_config()\n",
    "        self.redis = self._connect()\n",
    "```\n",
    "##### 2.2配置读取与建立连接\n",
    "```python\n",
    "def _init_config(self):\n",
    "    \"\"\"初始化配置\"\"\"\n",
    "    cf = ConfigParser()\n",
    "    self.config = {\n",
    "        'host': cf.get('redis', 'host'),\n",
    "        'port': cf.get('redis', 'port'),\n",
    "        'username': cf.get('redis', 'username'),\n",
    "        'password': cf.get('redis', 'password'),\n",
    "        'db': cf.get('redis', 'db'),\n",
    "        'nodes': cf.get('redis', 'nodes', fallback='')\n",
    "    }\n",
    "\n",
    "def _connect(self):\n",
    "    \"\"\"建立redis连接\"\"\"\n",
    "    try:\n",
    "        if self.config['nodes']:\n",
    "            # 集群模式\n",
    "            nodes = self._parse_cluster_nodes()\n",
    "            return RedisCluster(starup_nodes=nodes)\n",
    "        else:\n",
    "            # 单节点模式\n",
    "            pool = redis.ConnectionPool(\n",
    "                host=self.config['host'],\n",
    "                port=int(self.config['port']),\n",
    "                username=self.config['username'],\n",
    "                password=self.config['password'],\n",
    "                db=int(self.config['db'])\n",
    "            )\n",
    "            return redis.Redis(connection_pool=pool)\n",
    "    except Exception as e:\n",
    "        print(f\"Redis连接失败：{e}\")\n",
    "        raise e\n",
    "```\n",
    "\n",
    "##### 2.3数据操作方法\n",
    "```python\n",
    "def get(self, key):\n",
    "    \"\"\"获取数据\"\"\"\n",
    "    try:\n",
    "        value = self.redis.get(key)\n",
    "        if isinstance(value, bytes):\n",
    "            value = value.decode('utf-8')\n",
    "        return value\n",
    "    except Exception as e:\n",
    "        self._handle_error(e)\n",
    "        return None\n",
    "def set(self, key, value, expire=None):\n",
    "    \"\"\"设置数据\"\"\"\n",
    "    try:\n",
    "        return self.redis.set(key, value, ex=expire)\n",
    "    except Exception as e:\n",
    "        self._handle_error(e)\n",
    "```\n",
    "\n",
    "##### 2.4异常处理\n",
    "```python\n",
    "@classmethod\n",
    "def _handle_error(cls, e):\n",
    "    \"\"\"统一异常处理\"\"\"\n",
    "    if \"MOVED\" in str(e):\n",
    "        print(\"请检查redis是否使用了集群模式或者主从复制\")\n",
    "        print(\"数据被迁移到了另一个redis实例\")\n",
    "    print(f\"redis操作错误：{e}\")\n",
    "    raise e\n",
    "```\n",
    "\n",
    "#### 3.使用示例\n",
    "```python\n",
    "# 初始化redis客户端\n",
    "redis_client = RedisClient()\n",
    "\n",
    "# 获取数据\n",
    "value = redis_client.get(\"test_key\")\n",
    "print(f\"获取的值：{value}\")\n",
    "\n",
    "# 设置数据\n",
    "redis_client.set(\"test_key\", \"test_value\", expire=300) # 五分钟过期\n",
    "```\n",
    "\n",
    "#### 4.核心特征\n",
    "1. 支持单节点和集群两种模式\n",
    "2. 配置与代码分离，通过配置文件统一管理\n",
    "3. 自动识别环境并选择对应的连接方式\n",
    "4. 统一的api接口，对上层应用透明\n",
    "5. 异常统一处理\n",
    "6. 数据类型自动转换\n",
    "\n",
    "#### 5.注意事项\n",
    "1. 根据实际环境选择合适的部署模式\n",
    "2. 建议添加连接池管理和连接释放机制\n",
    "3. 可以根据需要扩展更多的redis操作方法\n",
    "4. 生产环境中需要考虑连接重试、超时等机制\n",
    "\n",
    "通过这样的封装，我们实现了一个既支持单节点又支持集群环境的redis工具类，具有以下优势：\n",
    "- 统一的配置管理\n",
    "- 简单的数据操作接口\n",
    "- 完善的异常处理机制\n",
    "- 数据类型自动转换\n",
    "- 良好的可扩展性"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
